//
// Morale/Luck Boosters - Temple adventure screen object handler
//
//

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adv_temple.h"
#include "adv_object_type.h"
#include "adventure_frame.h"
#include "adventure_sounds.h"
#include "alignment_relationship.h"
#include "army.h"
#include "basic_dialog.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_ptr.h"
#include "bitmap_layer_cache_window.h"
#include "bitmap_layer_cache_window_ptr.h"
#include "creature_ability.h"
#include "creature_icon_window.h"
#include "creature_stack.h"
#include "external_string.h"
#include "format_string.h"
#include "morale_icon_window.h"
#include "mouse_event.h"
#include "music.h"
#include "object_registration.h"
#include "player.h"
#include "random.h"
#include "replace_keywords.h"
#include "simple_dialog.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town_type.h"

namespace
{
	int const k_current_random_map_format_version = 1;

	t_object_registration<t_adv_temple> k_registration( k_adv_object_temple );
	t_object_registration<t_random_temple> k_random_registration( k_adv_object_random_temple );

	char const* k_model_name[] =
	{ 
		"moral-luck boosters.Temple of Light", 
		"moral-luck boosters.Temple of Order", 
		"moral-luck boosters.Temple of Darkness", 
		"moral-luck boosters.Temple of Chaos", 
		"moral-luck boosters.Temple of Nature", 
	};
}

// grab this for the creature frames
extern t_bitmap_group_cache g_creature_rings;
extern t_bitmap_group_cache const		k_morale_icons_34;



//
// +2 Morale for all Creatures or same alignment, +1 for allied alignments, zippo for hostile alignments
//

// -------------------------------------------------------
// Temple object constructor
// -------------------------------------------------------
t_adv_temple::t_adv_temple( std::string const& model_name)
			  : t_stationary_adventure_object( model_name )
{

}

t_adv_temple::t_adv_temple( t_town_type type )
                  : t_stationary_adventure_object( k_model_name[type] )
{

}

// -------------------------------------------------------
// create a single window from a group of windows
// -------------------------------------------------------
static void show_bonus( t_creature_stack& creature, int amount,
					    t_qualified_adv_object_type const& temple_type,
						t_basic_dialog* dialog )
{
	t_window*						parent;
	t_screen_rect                   rect;
	t_morale_icon_display*          morale;
	t_screen_point                  center;

	creature.add_bonus(k_stat_morale, amount, temple_type );
	// create invisible parent to house 2 icons and a text window
	parent = new t_window( t_screen_rect(0,0,0,0), t_window::k_completely_transparent, dialog );
	// create and add in the moral icon
	morale = new t_morale_icon_display( t_screen_rect(0,0,34,34), parent );
	morale->set_value( amount );
	center.x = morale->get_width() / 2;
	center.y = morale->get_height() + 5;

	// create and add the text window do display the bonus
	int const      k_text_width = 34;
	int const      k_text_height = 18;
	std::string    text;
	t_text_window* text_window;
	t_screen_rect  text_rect(-k_text_width / 2,0, k_text_width / 2, k_text_height);

	text_rect += center;
	text = format_string("+%i", amount );

	text_window = new t_text_window( get_font( text_rect.height() ), text_rect, parent, 
		                             text, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_center_horizontal();

	// add the portrait window
	t_window* window;

	center.y = text_rect.bottom + 5;

	rect = t_screen_rect(0,0,52,52);
	window = new t_creature_icon_window( rect, parent, &creature );

	rect = window->get_client_rect();
	rect -= t_screen_point( rect.width() / 2, 0 );
	rect += center;
	window->move( rect );
	parent->set_size_from_children();
	dialog->add_display_window( parent, creature.get_name() );
}

// -------------------------------------------------------
// Temple right click info
// -------------------------------------------------------
enum t_temple_result
{
	k_result_hostile,
	k_result_no_benefit,
	k_result_some_benefit,
	k_result_all_benefit
};

static t_temple_result get_result( t_army const* army, t_town_type alignment,
								   t_qualified_adv_object_type const& temple_type )
{
	bool				    any_creatures = false; // set if any creature gets a morale bonus
	bool				    all_hostile = true;
	bool				    some_sitting = false;
	t_creature_array const& creatures = army->get_creatures();
	int					    i;

	for (i = 0; i < t_creature_array::k_size; i++)
	{

		if (creatures[i].get_number() == 0)
			continue;

		t_alignment_relationship relationship;
		
		relationship = get_alignment_relationship( creatures[i].get_alignment(),
			                                       alignment );
		if (relationship < k_alignments_neutral )
		{
			all_hostile = false;
			if ( !creatures[i].has_temporary_bonus(temple_type) 
				 && !creatures[i].has_ability( k_ability_mechanical )
				 && !creatures[i].has_ability( k_ability_undead )) 
				any_creatures = true;
		} 
		else 
		{
			some_sitting = true;
		}
	}

	if ( all_hostile ) 
		return k_result_hostile;
	if (!any_creatures)
		return k_result_no_benefit;
	if (some_sitting)
		return k_result_some_benefit;
	return k_result_all_benefit;
}


// -------------------------------------------------------
// activate trigger for the Temple adventure map object
// -------------------------------------------------------

void t_adv_temple::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                               t_direction direction, t_adventure_frame* frame )
{
	int                  i;
	bool				 any_creatures = false; // set if any creature gets a morale bonus
	bool				 all_hostile = true;
	bool				 some_sitting = false;

	// loop through all creatures in the army and award temporary statistic based on subtype

	t_creature_array& creatures = army->get_creatures();

	t_basic_dialog* dialog;
	std::string     text;

	// grab the ring asset from the bitmap caches

	// grab the morale icon bonus icons
	dialog = new t_basic_dialog;

	for (i = 0; i < t_creature_array::k_size; i++)
	{

		if (creatures[i].get_number() == 0)
			continue;

		if (creatures[i].is_dead())
			continue;

		t_alignment_relationship relationship;
		
		relationship = get_alignment_relationship( creatures[i].get_alignment(),
			                                       get_alignment() );

		if ( !creatures[i].has_temporary_bonus(get_type()) 
			 && !creatures[i].has_ability( k_ability_mechanical )
			 && !creatures[i].has_ability( k_ability_undead )) 

		{
			switch (relationship)
			{
				case k_alignments_identical:
					show_bonus( creatures[i], 2, get_type(), dialog );
					any_creatures = true;
					break;
				case k_alignments_allied:
					show_bonus( creatures[i], 1, get_type(), dialog );
					any_creatures = true;
					break;
			}
		}
		if (relationship <= k_alignments_allied)
			all_hostile = false;
	}

	// determine what response to print
	if (!army->get_owner()->is_computer())
	{	
		if ( all_hostile ) 
			// display the appropriate hostile message
			text = get_text( "pray.negative" );
		else if (!any_creatures)
			text = get_text( "pray.empty" );
		else
			text = get_text( "pray.positive" );	// everyone got benefit
		dialog->set_text( text );
		dialog->add_ok_button();
		dialog->set_title( get_name() );
		dialog->open( get_dialog_bottom( point ), true, k_align_bottom );
		t_sound_cache music = get_music_playing();
		stop_music();
		get_dialog_sound( k_dialog_sound_morale )->play( get_sound_volume() );
		dialog->run_modal();
		play_music( music );
	}

}

// -------------------------------------------------------
// Temple right click info
// -------------------------------------------------------
void t_adv_temple::right_click( t_mouse_event const& event,
		                        t_adventure_frame* adventure_frame )
{
	t_army*              army = adventure_frame->get_selected_army();
	std::string			 help_text;

	if (army == 0)
	{
		help_text = get_text( "help.pray.some" );
	}
	else
	{
		t_temple_result      benefit = get_result( army, get_alignment(), get_type() );

		switch (benefit)
		{
			case k_result_hostile:
				// display the appropriate hostile message
				help_text = get_text( "help.pray.negative" );
				break;

			case k_result_no_benefit:
				help_text = get_text( "help.pray.empty" );
				break;

			case k_result_some_benefit:
				// display the appropriate success message
				help_text = get_text( "help.pray.some" );
				break;

			default:
				help_text = get_text( "help.pray.positive" );	// everyone got benefit
				break;
		}
	}
	show_popup_text( help_text, event.screen_point );
}

// -------------------------------------------------------
// Temple right click info
// -------------------------------------------------------
extern t_external_string const k_text_no_benefit;

std::string t_adv_temple::get_balloon_help() const
{
	t_adventure_frame*   adventure_frame = get_adventure_frame();
	t_army*              army = adventure_frame->get_selected_army();
	std::string          help_text;

	help_text = get_name();
	if (army == 0)
		return help_text;

	t_temple_result      benefit = get_result( army, get_alignment(), get_type() );

	if (benefit == k_result_no_benefit || benefit == k_result_hostile)
	{
		help_text += "\n";
		help_text += k_text_no_benefit;
	}
	return help_text;
}



//
//
// Random Temple 
//
//

t_random_temple::t_random_temple( std::string const& model_name )
	: t_stationary_adventure_object( model_name ),
	  m_alignment( k_town_life )
{
}

// -------------------------------------------------------
// -------------------------------------------------------
bool t_random_temple::read_from_map(
	std::streambuf &		buffer,
	t_progress_handler * )
{
	int version = get< t_uint16 >( buffer );
	if ( version < 0 || version > k_current_random_map_format_version )
		return false;

	if ( version > 0 )
	{
		if ( !m_linkage_info.read_from_map( buffer ) )
			return false;
	}
	else
	{
		m_linkage_info.reset();
	}

	return true;
}

// -------------------------------------------------------
// -------------------------------------------------------
bool t_random_temple::preplacement( t_adventure_map& map, int pass )
{
	if (t_stationary_adventure_object::preplacement( map, pass ))
		return true;

	switch( m_linkage_info.get_link_alignment( map, pass ) )
	{
		case t_linkage_data::k_link_alignment_life:
			m_alignment = k_town_life;
			return false; 

		case t_linkage_data::k_link_alignment_order:
			m_alignment = k_town_order;
			return false; 

		case t_linkage_data::k_link_alignment_death:
			m_alignment = k_town_death;
			return false; 

		case t_linkage_data::k_link_alignment_chaos:
			m_alignment = k_town_chaos;
			return false; 

		case t_linkage_data::k_link_alignment_nature:
			m_alignment = k_town_nature;
			return false; 

		case t_linkage_data::k_link_alignment_wait:
			return true; 

		default:
			assert(false);
			// Fall through to:

		case t_linkage_data::k_link_alignment_might:
		case t_linkage_data::k_link_alignment_any:
			m_alignment = random( k_magic_town_type_count );
			return false; 
	}
}

// -------------------------------------------------------
// -------------------------------------------------------
void t_random_temple::place( t_adventure_map& map, t_adv_map_point const& point )
{
	t_adv_temple*		temple;

	temple = new t_adv_temple( m_alignment );
	temple->place( map, point );
}
